/****************************************************************************
 ****	Fonts and memory management (mostly 1992-94)
 ***************************************************************************/


#ifndef _MSC_VER
#include <unistd.h>
#include <dirent.h>
#else
#include <userenv.h>
#include <io.h>
#include <direct.h>
#endif

#include <sys/stat.h>
#include <string.h>
#include <time.h>
#include <setjmp.h>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "dvi.h"
#include "dvi_para.h"
#include "dvi_subs.h"
#include "dvi_macr.h"


// forward declaration
VOID font_message( DVI_DOC *doc, UBYTE *str, FONT *fnt );


VOID font_free( DVI_DOC *doc, FONT *fnt )
{
	SWORD i;

	if( fnt->status.vf ) {
		/* free all fonts freigeben (including vfonts) */
		for( i = 0; i < fnt->max_vfonts; i++ ) {
			font_free( doc, fnt->vfonts[i] );
		}
	}

	if( fnt->zeichen > 0L ) {
		for( i = 0; i < fnt->ende-fnt->start; i++ ) {
			if( fnt->zeichen[i].daten > 0L ) {
				free( fnt->zeichen[i].daten );
			}
			fnt->zeichen[i].daten = 0L;
		}
		free( fnt->zeichen );
		fnt->zeichen = 0L;
	}
	fnt->status.geladen = FALSE;
	if( fnt->img > 0L ) {
		free( fnt->img );
	}
	fnt->img = 0L;
}


/* free some font in case of no memory font */
SWORD free_font( DVI_DOC *doc, BOOLEAN biggest )
{
	LONG max_len = -1, min_count = 0x7FFFFFFFL;
	SWORD i, len = -1, count = -1, anzahl = 0;

	for( i = 0; i < doc->max_font; i++ ) {
		if( doc->fonts[i]->status.geladen  &&  !doc->fonts[i]->status.aktuell ) {
			anzahl++;
			if( max_len < doc->fonts[i]->len ) {
				len = i;
				max_len = doc->fonts[i]->len;
			}
			if( min_count >= doc->fonts[i]->count ) {
				if((count < 0)||(doc->fonts[i]->len > doc->fonts[count]->len)) {
					count = i;
				}
				min_count = doc->fonts[i]->count;
			}
		}
	}

	if( !biggest ) {
		len = count;
	}
	if( len >= 0 ) {
		font_message( doc, "Free largest font: ", doc->fonts[len] );
		font_free( doc, doc->fonts[len] );
	}

	return ( anzahl );
}


/* Gibt eine Seite frei */
BOOLEAN free_page( DVI_DOC *doc )
{
	SWORD max_unused = -1, i, oldest = -1;

	for( i = 0; i < doc->limit_seiten; i++ ) {
		if((doc->seiten[i] > 0L)&&(doc->seiten[i]->bitmap > 0L)) {
			if((max_unused < doc->seiten[i]->unused)&&(doc->seite != i)&&(doc->dseite != i)) {
				oldest = i;
				max_unused = doc->seiten[i]->unused;
			}
			( doc->seiten[i]->unused )++;
		}
	}

	if((oldest < 0)||(oldest > doc->limit_seiten)) {
		return ( FALSE );
	}

	WriteLN( doc, "Lagere �lteste Seite aus!" );
	Mfree( doc->seiten[doc->dseite]->bitmap );
	doc->seiten[oldest]->bitmap = 0L;
	return ( TRUE );
}


/* Sucht Zeichensatz (und sp�ter Seite) zum Auslagern */
VOID find_free_mem( DVI_DOC *doc, LONG left )
{
	extern jmp_buf ende;                                            /* aus darst_dvi.c */
	SWORD i;

#ifdef PAS_FLIB
	/* Flib-Informatioen werden nicht mehr gebraucht */
	if( a_flib > 0 ) {
		Mfree( a_flib );
		a_flib = 0L;
		return;
	}
#endif
	for( i = 0; i < doc->no_of_flib; i++ ) {
		if( doc->flib[i] > 0 ) {
			free( doc->flib[i] );
			doc->flib[i] = 0L;
			return;
		}
	}

	/* Speichersparend: Fonts freigeben! */
	while( !doc->cache_all  &&  free_font( doc, TRUE ) ) {
		return; /* Zuerst Seiten, dann Fonts */
	}
#ifdef __MSDOS__
	while( GlobalCompact( left ) < left )
#else
	do
#endif
	{
		if( !free_page( doc )  &&  !free_font( doc, TRUE ) ) {
			if( doc->cache_all ) {
				LONG pos;

				doc->cache_all = FALSE;
				pos = (LONG)doc->cp-(LONG)doc->cache;
				fill_cache( doc, doc->seiten[doc->seite]->fpos, doc->seiten[doc->seite]->end_pos );
				doc->cp += pos-( doc->fpos );
				return;
			}
#ifndef __MSDOS__
			if( !PRINTING  &&(doc->seiten[doc->dseite]->bitmap > 0L)) {  /* angezeigte Seite l�schen (letzte Chance!) */
				while( MiNT  &&  is_prn() ) {
					if( scan_event( 50 ) ) {
						longjmp( ende, -9876 );  /* Beende lesen */
					}
				}
				if( !is_prn() ) {
					Mfree( doc->seiten[doc->dseite]->bitmap );
					doc->seiten[doc->dseite]->bitmap = 0L;
				}
			}
			else
#endif
			{
				if( MEMORY_FREE == 1 ) {
					/* Kein freier Speicher gefunden! */
					Tos_Fatal( doc, 0, ENDOFMEM );
				}
				MEMORY_FREE = 1;
				return;
			}
		}
	} /* Unter Windows eine while-Schleife */
#ifndef __MSDOS__
	while( (long)Malloc( -1L ) < left ) {}
#endif
}


VOID font_message( DVI_DOC *doc, UBYTE *str, FONT *fnt )
{
#ifdef DEBUG_FONT
	UBYTE mess[40], *c = "";

	Message( doc, str );
	if( fnt->name[9] == '*' ) {
		c = "Replaced by ";
	}
	sprintf( mess, "%s %.9s (scaled %d.%.3d)", c, fnt->name, fnt->size/1000, fnt->size%1000 );
	WriteLN( doc, mess );
#else
	UBYTE *c;

	Message( doc, str );
	if( VERSION == LINDNER_TEX ) {
		c = strstr( fnt->datei, "\\mag" );
	}
	else {
		c = strstr( fnt->datei, "\\font" );
	}
	if( c > 0L ) {
		WriteLN( doc, c+1 );
	}
	else {
		WriteLN( doc, fnt->datei );
	}
#endif
}


/****************************************************************************/

extern char get_bit( void );
extern long get_nibble( void );
extern long pk_packed_number( DVI_DOC *doc );


LONG repeat_count = 0, dyn_f;
UBYTE *decode_ptr, decode_gerade = 0, decode_bit = 8;
#ifdef __MSDOS__
DVI_DOC *ph;
#endif


VOID decode_pk_char( DVI_DOC *doc, ZCHN *chr )
{
	UBYTE *last_line_start, *cur_byte, *src, *dest;
	LONG cur_pos, run_count, w, h;
	UBYTE cur_bit, color;

	/* Sollte eigentlich nicht vorkommen!*/
	if( chr->fpos == 0L ) {
		return;
	}
#ifdef __MSDOS__
	ph = doc;
#endif
	last_line_start = cur_byte = chr->daten;
	cur_bit = 0x80;
	cur_pos = 0;
	decode_ptr = doc->a_font->img+chr->fpos;
	decode_gerade = 0;
	chr->i_tfm = h_to_pixel( doc, chr->tfm );
	if( ( chr->flag&0x0F ) > 7 ) {
		color = TRUE;
	}
	else {
		color = FALSE;
	}
	dyn_f = ( chr->flag )>>4;
	w = chr->w;
	h = chr->h;

	if( dyn_f != 14 ) {
		while( h > 0 ) {
			run_count = pk_packed_number( doc );
			do {
				while( cur_pos < w  &&  run_count > 0 ) {
					if( color ) {
						*cur_byte |= cur_bit;
					}
					cur_bit >>= 1;
					if( cur_bit == 0 ) {
						cur_byte++;
						cur_bit = 0x80;
					}
					cur_pos++;
					run_count--;
				}
				if( cur_pos >= w ) {
					h--;
					if( cur_bit != 0x80 ) {
						cur_byte++, cur_bit = 0x80;
					}
					while( repeat_count > 0 ) {
						src = last_line_start;
						dest = cur_byte;
						while( src < cur_byte ) {
							*dest++ = *src++;
						}
						last_line_start = cur_byte;
						cur_byte = dest;
						repeat_count--;
						h--;
					}
					last_line_start = cur_byte;
					cur_pos = 0;
				}
				if( run_count == 0 ) {
					color = !color;
				}
			} while( run_count > 0 );
		}
	}
	else {
		decode_bit = 0;
		while( h > 0 ) {
			cur_bit = 0x80;
			while( w > 0 ) {
				if( get_bit() ) {
					*cur_byte |= cur_bit;
				}
				cur_bit >>= 1;
				if( cur_bit == 0 ) {
					cur_bit = 0x80;
					cur_byte++;
				}
				w--;
			}
			w = chr->w;
			h--;
			if( cur_bit != 0x80 ) {
				cur_byte++;
			}
		}
	}
}


VOID lese_vfont( DVI_DOC *doc, FONT *fnt )
{
	UBYTE *ptr = fnt->img;
	LONG z, a, i, j, vfonts_nr = 0, chr = 0, faktor;

	fnt->max_vfonts = 0;
	fnt->ende = 16;
	while( ( fnt->zeichen = calloc( 16L, sizeof( ZCHN ) ) ) == 0L ) {
		find_free_mem( doc, 8000L );
	}
	while( ptr < fnt->img+fnt->len ) {
		i = 0;
		switch( *ptr++ ) {
		case pre:
			ptr++;
			ptr += ( *ptr )+1;
			if(( fnt->chk_sum != 0L) &&( fnt->chk_sum != get_long( &ptr )) ) {
				WriteLN( doc, "Wrong checksum!" );
			}
			fnt->de_size = get_long( &ptr );
			faktor = fnt->de_size/fnt->at_size;
			fnt->font_space = fnt->at_size/6L;
			z = fnt->at_size;
			a = 4;
			while( i > 0x800000L ) {
				z >>= 1;
				a++;
			}
			a = 8-a;
			fnt->at_size = a;
			fnt->de_size = z;
			break;

		case fnt_def4:
			i = (UBYTE)*ptr++;

		case fnt_def3:
			i = ( i<<8 ) + (UBYTE)*ptr++;

		case fnt_def2:
			i = ( i<<8 ) + (UBYTE)*ptr++;

		case fnt_def1:
			i = ( i<<8 ) + (UBYTE)*ptr++;
			if( fnt->max_vfonts <= vfonts_nr ) {
				FONT **old;

				if( ( old = (FONT**)calloc( fnt->max_vfonts+8L, sizeof( FONT* ) ) ) == 0L ) {
					Tos_Fatal( doc, (SWORD)old, ENDOFMEM );
				}
				if(( fnt->vfonts > 0L) &&( fnt->max_vfonts > 0) ) {
					memcpy( old, fnt->vfonts, fnt->max_vfonts*sizeof( FONT* ) );
					free( fnt->vfonts );
				}
				fnt->vfonts = old;
				fnt->max_vfonts += 8;
			}

			while( ( fnt->vfonts[vfonts_nr] = (FONT*)calloc( 1L, sizeof( FONT ) ) ) == 0L ) {
				find_free_mem( doc, 8000L );
			}
			fnt->vfonts[vfonts_nr]->id = i;
			fnt->vfonts[vfonts_nr]->chk_sum = get_long( &ptr );
			fnt->vfonts[vfonts_nr]->at_size = get_long( &ptr );
			fnt->vfonts[vfonts_nr]->de_size = get_long( &ptr );
			i = *ptr++ + *ptr++;
			if( i > 0 ) {
				memcpy( fnt->vfonts[vfonts_nr]->datei, ptr, i );
				fnt->vfonts[vfonts_nr]->datei[i] = 0;
				ptr += i;
			}
			else {
				i = 0;
			}
			fnt->vfonts[vfonts_nr]->datei[i+1] = 0;
			i = ( ( faktor*doc->mag*( fnt->vfonts[vfonts_nr]->at_size>>4 ) )/( fnt->vfonts[vfonts_nr]->de_size>>4 ) ) >>4;
			finde_font( doc, fnt->vfonts[vfonts_nr], i );
			vfonts_nr++;
			break;

		case post:
			fnt->max_vfonts = vfonts_nr;
			return;

		case 242:
			a = get_long( &ptr );
			i = get_long( &ptr );
			j = get_vf_long( fnt->at_size, fnt->de_size, ptr );
			goto new_char;

		default:
			if( *( --ptr ) > 243 ) {
				Warning( WNOCHAR );
				break;
			}
			a = *ptr++;
			i = *ptr;
			j = get_vf_long( fnt->at_size, fnt->de_size, ptr );
new_char:
			ptr += 4;
			/* get more memory */
			if( chr >= fnt->ende ) {
				ZCHN *z;
				while( ( z = calloc( fnt->ende+16L, sizeof( ZCHN ) ) ) == 0L ) {
					find_free_mem( doc, 8000L );
				}
				memcpy( z, fnt->zeichen, fnt->ende*sizeof( ZCHN ) );
				free( fnt->zeichen );
				fnt->zeichen = z;
				fnt->ende += 16L;
			}
			fnt->zeichen[chr].nr = i;
			fnt->zeichen[chr].dx = a;
			fnt->zeichen[chr].tfm = j;
			fnt->zeichen[chr].fpos = (LONG)( ptr-fnt->img );
			chr++;
			ptr += a;
			break;
		}
	}
}


/* reads a font into memory */
VOID lese_font( DVI_DOC *doc, FONT *fnt )
{
	ZCHN *a_char;
	LONG len, i, pl;
	LONG z, b, a;
	HANDLE fh;
	UBYTE *next_ptr, *ptr;
	LONG tfm, nr, dx, dy, w, h;
	LONG start = 0x7FFFFFFFL, ende = 0, max_zeichen;

	font_message( doc, "Load font: ", fnt );

	fh = (HANDLE)Fopen( fnt->datei, FO_READ );
	if( fh < 0 ) {
		Tos_Fatal( doc, (LONG)fh, ENOREPL );
	}

	if( fnt->status.flib ) {
		len = fnt->len;
		Fseek( fnt->offset, fh, 0 );
	}
	else {
		len = Fseek( 0L, fh, 2 );
		Fseek( 0L, fh, 0 );
	}
	while( ( ptr = malloc( len ) ) == 0L ) {
		find_free_mem( doc, 8000L );
	}
	i = Fread( fh, len, ptr );
	Fclose( fh );
	fnt->img = ptr;
	fnt->len = i;

	if( fnt->status.vf ) {
		/* load virtuell font */
		lese_vfont( doc, fnt );
		return;
	}

	max_zeichen = 128;
	while( ( fnt->zeichen = calloc( 128L, sizeof( ZCHN ) ) ) == 0L ) {
		find_free_mem( doc, 8000L );
	}
	while( *ptr != PK_POST  &&  ptr-len < fnt->img ) {
		i = *ptr++;
		switch( (SWORD)i ) {
		case PK_XXX1:
			ptr += *ptr+1;
			break;

		case PK_XXX2:
			ptr += ( *ptr<<8 ) + *( ptr+1 ) + 2;
			break;

		case PK_XXX3:
			ptr += ( *ptr<<16 ) + ( *( ptr+1 )<<8 ) + *( ptr+2 ) + 3;
			break;

		case PK_XXX4:
			ptr += ( *ptr<<24 ) + ( *( ptr+1 )<<16 ) + ( *( ptr+2 )<<8 ) + *( ptr+3 ) + 4;
			break;

		case PK_YYY:
			ptr += 4;

		case PK_NOP:
			break;

		case PK_PRE:
			if( PK_ID != *ptr++ ) {
				Tos_Fatal( doc, 0, EPKFORM );
			}
#ifdef __MSDOS__
			i = get_byte( &ptr );
			ptr += i;
#else
			ptr += *ptr+1;
#endif
			fnt->de_size = get_long( &ptr );
			fnt->font_space = fnt->at_size/6L;
			z = fnt->at_size;
			a = 4;
			while( z > 0x800000L ) {
				z >>= 1;
				a += 1;
			}
			b = 8-a;
			a = get_long( &ptr );
			if(( fnt->chk_sum != 0L) &&( fnt->chk_sum != a) ) {
				Warning( WCHKSUM );
			}
			ptr += 8;
			break;

		default:
			if( i >= 0xF0 ) {
				Tos_Fatal( doc, 0, EPKFORM );
			}
			if( ( i&7 ) < 4 ) {
				pl = ( ( i&3 )<<8 ) + *ptr++;
				nr = *ptr;
				next_ptr = ptr+pl+1;
				tfm = get_vf_long( b, z, ptr );
				ptr += 5;		/* nr+dm+tfm */
				w = *ptr++;
				h = *ptr++;
				dx = ext_byte( *ptr++ );
				dy = ext_byte( *ptr );
			}
			else if( ( i&7 ) < 7 ) {
				pl = ( i&3 )*65536L + get_word( &ptr );
				nr = *ptr;
				next_ptr = ptr+pl+1;
				tfm = get_vf_long( b, z, ptr );
				ptr += 6;		/* nr+dm+tfm */
				w = get_word( &ptr );
				h = get_word( &ptr );
				dx = ext_word( get_word( &ptr ) );
				dy = ext_word( get_word( &ptr ) );
				ptr--;
			}
			else {
				pl =  get_long( &ptr );
				nr = get_long( &ptr );
				next_ptr = ptr+pl;
				tfm = get_vf_long( b, z, ptr );
				if( *ptr != 0 ) {
					tfm -= a;
				}
				ptr += 12;		/* tfm+dx+dy (oder h_off, v_off) */
				w = get_long( &ptr );
				h = get_long( &ptr );
				dx = get_long( &ptr );
				dy = get_long( &ptr );
				ptr--;
			}

			/* may need more ram */
			if( max_zeichen <= nr ) {
				while( ( a_char = calloc( ( nr+255 )>>8, 256*sizeof( ZCHN ) ) ) == 0L ) {
					find_free_mem( doc, 8000L );
				}
				memcpy( a_char, fnt->zeichen, max_zeichen*sizeof( ZCHN ) );
				max_zeichen = 256*( ( nr+255 )>>8 );
				free( fnt->zeichen );
				fnt->zeichen = a_char;
			}

			/* new start letter? */
			if( start > nr ) {
				if( nr < 0 ) {
					Tos_Fatal( doc, 0, EPKFORM );
				}
				start = nr;
			}

			/* new end letter? */
			if( ende < nr ) {
				ende = nr;
			}
			a_char = &fnt->zeichen[nr];
			a_char->nr = nr;
			a_char->w = w;
			a_char->h = h;
			a_char->dx = dx;
			a_char->dy = dy;
			a_char->tfm = tfm;
			a_char->i_tfm = 0L;
			a_char->fpos = (LONG)( ptr-fnt->img );
			a_char->flag = (SWORD)i;
			a_char->daten = 0L;
			ptr = next_ptr;
			break;
		}
	}

	ende++;
	if( start > 0 ) {
		memcpy( fnt->zeichen, &fnt->zeichen[start], ( ende-start )*sizeof( ZCHN ) );
	}

	if( ende-start != max_zeichen ) {
		a_char = realloc(  fnt->zeichen, ( ende-start )*sizeof( ZCHN ) );
		if( a_char > 0L ) {
			fnt->zeichen = a_char;
		}
	}
	fnt->start = start;
	fnt->ende = ende;
}


/******************************************************************************/


VOID lade_font( DVI_DOC *doc, LONG fontnr )
{
	SWORD i;

	if((doc->fonts[doc->font]->id == fontnr)&&  doc->fonts[doc->font]->status.aktuell ) {
		return;
	}
	doc->fonts[doc->font]->status.aktuell = FALSE;
	for( i = 0; i < doc->max_font; i++ ) {
		if( ( doc->fonts[i]->id ) == fontnr ) {
			doc->font = i;
			if( !doc->fonts[doc->font]->status.geladen ) {
				lese_font( doc, doc->fonts[doc->font] );
				doc->fonts[doc->font]->count = doc->fonts[doc->font]->nachgeladen;
				doc->fonts[doc->font]->nachgeladen += 5;
			}
			doc->a_font = doc->fonts[doc->font];
			doc->a_font->count++;
			doc->a_font->status.aktuell = TRUE;
			doc->a_font->status.geladen = TRUE;
			doc->font_space = doc->fonts[doc->font]->font_space;
			return;
		}
	}
	Tos_Fatal( doc, (SWORD)fontnr, EUNDEF );
}


/******************************************************************************/
/* Ab hier Suchen von Zeichens�tzen */

extern SWORD aktuell;
HANDLE miss;

VOID add_to_miss( DVI_DOC *doc, UBYTE *dvi, UBYTE *font, LONG mag )
{
	UBYTE str[MAX_PATH_LEN], str2[MAX_PATH_LEN], *right;

	strcpy( str, MISSING );          /* Default */
	if( VERSION == STRUNK_TEX ) { /* So soll es wohl sein... */
		strcpy( str, dvi );
		strcpy( str+strlen( str )-4, ".fts" );
	}
	if((miss <= 0)&&(( miss = (HANDLE)Fopen( str, O_RDWR ) ) <= 0)) {
		miss = (HANDLE)Fcreate( str, 0 );
		if( miss <= 0 ) {
			Warning( WNOMISS );
			return;
		}
		if( VERSION == STRUNK_TEX ) {
			Fwrite( miss, 3L, "%\xD\xA" );
		}
	}
	Fseek( 0L, miss, 0 );
	if( VERSION == LINDNER_TEX ) {
		sprintf( str, "res%ld.%.3s %s %.1ld.%.3ld\xD", H_DPI, TREIBER_NAME, font, mag/1000L, mag%1000L );
	}
	else {
		sprintf( str, "%s in magnification %ld\xD", font, mag );
	}
	/* Nachsehen, ob nicht eh schon in mache */
	while( read_datei_str( miss, str2 ) >= 0  &&  strstr( str, str2 ) == 0L ) {
	}
	/* if not: add to missing list */
	if( strstr( str, str2 ) == 0L ) {
		write_datei_str( miss, str );
	}

	// announce
	sprintf( str, "missing: \"%s\" in %li.%03li (%li dpi)", font, mag/1000l, mag%1000l, (H_DPI*mag)/1000 );
	WriteLN( doc, str );

	/* ok we will use our own directory structure (some as Strunk-TeX for ATARI TOS ...)
	    ...font300\1000\cmr10.pk
	 */

	// first call metatfont /assumes mf is in the path)
	{
		char path[MAX_PATH_LEN];
		HANDLE hProcessToken;
		int hdpi = (H_DPI*mag+500)/1000;

		OpenProcessToken( GetCurrentProcess(), TOKEN_IMPERSONATE|TOKEN_QUERY|TOKEN_DUPLICATE, &hProcessToken );
		ExpandEnvironmentStringsForUser( hProcessToken, "%APPDATA%\\DVI", path, MAX_PATH_LEN );
		mkdir( path );
		sprintf( str, "%s\\%s", path, TREIBER_NAME );
		mkdir( str );
		chdir( str );

		sprintf( str, "mf.exe \\scrollmode; mode:=%s; mag:=%li.%03li; input \"%s\"", TREIBER_NAME, mag/1000l, mag%1000l, font );
		WriteLN( doc, str );
		system( str );

		sprintf( str, "%s%\\%s\\font%04i", path, TREIBER_NAME, hdpi );
		WriteLN( doc, str );
		mkdir( str );

		sprintf( str, "gftopk.exe %s.%igf font%04i\\%s.pk", font, hdpi, hdpi, font );
		WriteLN( doc, str );
		system( str );

		sprintf( str, "del %s.%igf %s.tfm %s.log", font, hdpi, font, font );
		WriteLN( doc, str );
		system( str );
	}
	return;

#if 0
	// manual font creation via script
	right = strrchr( MISSING_FONT_GENERATE, '\\' );
	if(  right  ) {
		// ok window cannot execute system commands with spaces in their path (wow, so stupid). Lets work around ...
		char path[MAX_PATH_LEN];
		HANDLE hProcessToken;

		sprintf( str, "%s \"%s\\font%04i\\\" \"%s\" %li.%03li %s %li", right+1, doc->suchpfad1, (H_DPI*mag)/1000, font, mag/1000l, mag%1000l, TREIBER_NAME, (H_DPI*mag)/1000 );
		WriteLN( doc, str );

		OpenProcessToken( GetCurrentProcess(), TOKEN_IMPERSONATE|TOKEN_QUERY|TOKEN_DUPLICATE, &hProcessToken );
		ExpandEnvironmentStringsForUser( hProcessToken, MISSING_FONT_GENERATE, path, MAX_PATH_LEN );
		*strrchr( path, '\\' ) = 0;
		chdir( path );
		system( str );
	}
	else {
		sprintf( str, "%s \"%s\\font%04i\\\" \"%s\" %li.%03li %s %li", MISSING_FONT_GENERATE, doc->suchpfad1, (H_DPI*mag)/1000, font, mag/1000l, mag%1000l, TREIBER_NAME, (H_DPI*mag)/1000 );
		WriteLN( doc, str );
		system( str );
	}
#endif
}


/* Liest Mattes-Flibs */
SWORD open_m_flib( DVI_DOC *doc, UBYTE *name )
{
	UBYTE *ptr;
	FLIB_HEAD flib_head;
	SWORD fnr;
	HANDLE hdl;

	if( doc->no_of_flib >= 16 ) {
		return ( -1 );      /* Too many Flib! */
	}
	fnr = doc->no_of_flib;

	if( ( hdl = (HANDLE)Fopen( name, FO_READ ) ) <= 0 )
#ifdef __MSDOS__
	{
		return ( -1 );
	}
#else
	{
		return ( hdl );
	}
#endif
	Fread( hdl, sizeof( FLIB_HEAD ), &flib_head );
	if( strstr( flib_head.magic, "FLIB\2" ) == 0L ) {
		Fclose( hdl );    /* Keine Flib! */
		if( strstr( doc->flib_head[fnr].magic, "FLIB" ) ) {
			return ( 1 );       /* Alte FLIB */
		}
		else {
			return ( 0 );       /* gar keine FLIB... */
		}
	}

	strcpy( doc->flib_name[fnr], name );
#ifndef __MSDOS__
	memcpy( &( doc->flib_head[fnr] ), &flib_head, sizeof( FLIB_HEAD ) );
#else
	ptr = ( (UBYTE*)&flib_head )+4;
	memcpy( doc->flib_head[fnr].magic, &flib_head.magic, 4 );
	doc->flib_head[fnr].version = get_word( &ptr );
	doc->flib_head[fnr].dir_len = get_word( &ptr );
	doc->flib_head[fnr].nsizes = get_word( &ptr );
	doc->flib_head[fnr].nfonts = get_word( &ptr );
	doc->flib_head[fnr].com_len = get_word( &ptr );
#endif
	Fseek( doc->flib_head[fnr].com_len, hdl, 1 );
	doc->flib[fnr] = malloc( doc->flib_head[fnr].dir_len+1 );
	if( doc->flib[fnr] <= 0L ) {
		return ( Fclose( hdl ) );     /* Kein Speicher mehr! */
	}
	if( doc->flib_head[fnr].dir_len != Fread( hdl, doc->flib_head[fnr].dir_len, doc->flib[fnr] ) ) {  /* Datei defekt! */
		free( doc->flib[fnr] );
		doc->flib[fnr] = 0L;
		return ( Fclose( hdl ) );
	}
	Fclose( hdl );
	doc->no_of_flib++;
	return ( doc->flib_head[fnr].version );
}


/* Liest alle vorhandenen Vergr��erungen ein */
SWORD read_mags( DVI_DOC *doc, UBYTE *s_pfad )
{
	UBYTE str[MAX_PATH_LEN], pfad[MAX_PATH_LEN];
	LONG hdl, i = 0, j;
	SWORD old_domain;

#ifndef __MSDOS__
	if( s_pfad[0] == 0 ) {
		return ( 0 );
	}
	while( doc->groessen[i] > 0 ) {
		i++;
	}
	if( !MiNT ) { /* Suche ohne MiNT */
		UBYTE spfad[128];
		DTA dta, *old;

		old = Fgetdta();
		Fsetdta( &dta );
		strcpy( spfad, s_pfad );
		strcat( spfad, "\\*.*" );
		hdl = Fsfirst( spfad, FA_SUBDIR );
		for( i = 0; i < 64  &&  hdl == 0; ) {
			if( dta.d_attrib&FA_SUBDIR ) {
				if( dta.d_fname[0] != '.' ) {
					if( VERSION == LINDNER_TEX ) {
						for( j = 4; dta.d_fname[j] == '_'; j++ ) {
						}
						doc->groessen[i++] = 1000*(SWORD)atol( dta.d_fname+j ) + (SWORD)atol( dta.d_fname+9 );
					}
					else if( VERSION == STRUNK_TEX ) {
						doc->groessen[i] = (SWORD)atol( dta.d_fname+4 );
						if( doc->groessen[i] > 0 ) {
							i++;
						}
					}
					else if( VERSION == EM_TEX ) {
						doc->groessen[i] = (SWORD)atol( dta.d_fname );
						if( doc->groessen[i] > 0 ) {
							i++;
						}
					}
				}
			}
			else {  /* Kein Directory, vielleicht FLIB? */
				sprintf( str, "%s\\%s", s_pfad, dta.d_fname );
				strlwr( str );
				/* Mattes-Flib? */
				if( ( j = open_m_flib( doc, str ) ) != 0x0200L ) {
					if( j == 1 ) {
						/* ist alte Flib */
						doc->groessen[i++] = (SWORD)-atol( str+2 );
					}
				}
			}
			hdl = Fsnext();
		}
		Fsetdta( old );
		return ( 0 );
	}

	old_domain = Pdomain( -1 );
	Pdomain( 1 );
	hdl = Dopendir( s_pfad, 0 );
	if( hdl < 0 ) {
		Pdomain( old_domain );
		return ( 0 );
	}
	while( 0 == Dreaddir( 36, hdl, str )  &&  i < 64 ) {
		if( str[4] == '.' ) {
			continue;
		}
		sprintf( pfad, "%s\\%s", s_pfad, str+4 );
		if( ( Fattrib( pfad, 0, 0 )&FA_SUBDIR ) == 0 ) {  /* vielleicht FLIB? */
			if( ( j = open_m_flib( doc, pfad ) ) == 0x0200L ) {
				/* ist Mattes-Flib */
				continue;
			}
			else if( j == 1 ) { /* ist alte Flib */
				doc->groessen[i++] = (SWORD)-atol( str+2+4 );
				continue;
			}
		}

		if( VERSION == LINDNER_TEX ) {
			for( j = 8; str[j] == '_'; j++ ) {
			}
			doc->groessen[i++] = 1000*(SWORD)atol( str+j ) + (SWORD)atol( str+9+4 );
		}
		else if( VERSION == STRUNK_TEX ) {
			doc->groessen[i] = (SWORD)atol( str+4 );
			if( doc->groessen[i] > 0 ) {
				i++;
			}
		}
		else if((VERSION == EM_TEX)||(VERSION == DIRECT_TEX)) {
			doc->groessen[i] = (SWORD)atol( str );
			if( doc->groessen[i] > 0 ) {
				i++;
			}
		}
	}
	Dclosedir( hdl );
	if( i == 0 ) {
		doc->groessen[i++] = 1;
	}
	while( i < 64 ) {
		doc->groessen[i++] = 0;
	}
	Pdomain( old_domain );
#else   // windows goes here!
	WIN32_FIND_DATA dta;
	HANDLE ff;

	if( s_pfad[0] == 0 ) {
		return ( 0 );
	}
	while( doc->groessen[i] > 0 ) {
		i++;
	}

	strcpy( pfad, s_pfad );
	strcat( pfad, "\\*.*" );
	ff = FindFirstFileA( pfad, &dta );
	if(  ff!= INVALID_HANDLE_VALUE  ) {
		do {
			if( dta.cFileName[0] != '.' ) {
				lstrcpy( str, s_pfad );
				lstrcat( str, "\\" );
				lstrcat( str, dta.cFileName );
				if( dta.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY ) { /* verm. Directory! */
					if( VERSION == LINDNER_TEX ) {
						for( j = 4; dta.cFileName[j] == '_'; j++ ) {
						}
						doc->groessen[i++] = 1000*(SWORD)atol( dta.cFileName+j ) + (SWORD)atol( dta.cFileName+9 );
					}
					else if( VERSION == STRUNK_TEX ) {
						doc->groessen[i] = (SWORD)atol( dta.cFileName+4 );
						if( doc->groessen[i] > 0 ) {
							i++;
						}
					}
					else if( VERSION == EM_TEX ) {
						doc->groessen[i] = (SWORD)atol( dta.cFileName );
						if( doc->groessen[i] > 0 ) {
							i++;
						}
					}
					else if( VERSION == MIK_TEX ) {
						if( strlen( dta.cFileName ) > 3 ) {
							doc->groessen[i] = (SWORD)atol( dta.cFileName+3 );
							if( doc->groessen[i] > 0 ) {
								i++;
							}
						}
					}
				}
				else {
					/* Kein Directory, vielleicht Mattes-Flib? */
					open_m_flib( doc, str );
				}
			}
		} while( FindNextFileA( ff, &dta ) );
		FindClose( ff );
	}
#endif
	return ( 0 );
}


/* Alte Flibs werden nicht mehr unterst�tzt! */
#ifdef PAS_FLIB
/* Findet Files in Flibs ohne Links */
SWORD open_a_flib( UBYTE *dat )
{
	SWORD hdl;
	LONG m;

	if( ( hdl = (SWORD)Fopen( dat, FO_READ ) ) < 0 ) {
		return ( hdl );
	}
	Fread( hdl, 4, &m );
	if( m != LIBMAGIC /*&&  m!=LNKMAGIC*/ ) {
		return ( Fclose( hdl ) );     /* Keine Flib bzw Link (noch nicht unterst�tzt)! */
	}
	Fread( hdl, 4, &m );     /* Zahl der Directory-Eintr�ge */
	no_of_direntry = m;
	a_flib = Malloc( sizeof( direntry )*m );
	if( a_flib <= 0L ) {
		return ( Fclose( hdl ) );     /* Kein Speicher mehr! */
	}
	if( sizeof( direntry )*m != Fread( hdl, sizeof( direntry )*m, a_flib ) ) {  /* Datei defekt! */
		Mfree( a_flib );
		a_flib = 0L;
		return ( Fclose( hdl ) );
	}
	return ( Fclose( hdl ) == 0 );
}


BOOLEAN find_a_flib( FONT *font )
{
	LONG i;

	for( i = 0; i < no_of_direntry  &&  a_flib[i].mname != strstr( a_flib[i].mname, font->datei ); i++ ) {
	}
	if( i >= no_of_direntry ) {
		return ( FALSE );   /* Nichts gefunden */
	}
	font->status.flib = TRUE;
	font->offset = a_flib[i].where;
	font->len = a_flib[i].size;
	return ( TRUE );
}


#endif

/* Hilfroutine zu find_m_flib */
BOOLEAN find_m_flib_font( UBYTE *name, UBYTE *pos, LONG nfonts, FONT_HEAD *fn )
{
	/* Zeichensatz suchen */
	do {
#ifndef __MSDOS__
		memcpy( fn, pos, 9L );  /* sizeof(FONT_HEAD) liefert 10 zur�ck!!! */
		pos += fn->namelen+9;
#else
		fn->len = get_long( &pos );
		fn->start = get_long( &pos );
		fn->namelen = *pos++;
		pos += (UBYTE)fn->namelen;
#endif
	} while( !( strlen( name ) == fn->namelen  &&  memcmp( pos-fn->namelen, name, fn->namelen ) == 0 )  &&  --nfonts > 0 );
	if( nfonts <= 0 ) {
		return ( FALSE );   /* Nichts gefunden */
	}
	return ( TRUE );
}


BOOLEAN find_m_flib( DVI_DOC *doc, FONT *font, LONG mag, LONG tol, SWORD fnr )
{
	SIZE_HEAD sz;
	FONT_HEAD fn;
	UBYTE *pos, str[128];
	LONG i, j, res, sizes[100], no_of_sizes;

	/* ".pk" abschneiden */
	strcpy( str, font->datei );
	pos = strrchr( str, '.' );
	if( pos > 0L ) {
		*pos = 0;
	}

	/* Aufl�sung und Toleranz berechnen */
	tol = ( tol*doc->h_dpi*8192L )/125L;
	if( (ULONG)tol > 0x10624DDl ) { /* �berlauf: Dann maximale Toleranz! */
		tol = 0x10624DDl;
	}
	res = ( ( mag*doc->h_dpi )/125L )*8192L;

	/* Gr��e suchen */
	pos = doc->flib[fnr];
	no_of_sizes = i = 0;
	do {
#ifndef __MSDOS__
		memcpy( &sz, pos, sizeof( SIZE_HEAD ) );
#else
		sz.len = get_word( &pos );
		sz.nfonts = get_word( &pos );
		sz.dpi = get_long( &pos );
		pos -= 8l;
#endif
		if( labs( sz.dpi-res ) < tol ) {
			sizes[no_of_sizes++] = labs( sz.dpi-res );
			sizes[no_of_sizes++] = (LONG)pos;
		}
		pos += sz.len+sizeof( SIZE_HEAD );
		i++;
	} while( i < doc->flib_head[fnr].nsizes );
	if( no_of_sizes == 0 ) {
		return ( FALSE );   /* Nichts gefunden */
	}
	for( i = 0; i < no_of_sizes/2; i++ ) {
		for( res = j = 0; j < no_of_sizes; j += 2 ) {
			if( sizes[j] < sizes[res] ) {
				res = j;
			}
		}
#ifndef __MSDOS__
		pos = (UBYTE*)( sizes[res+1]+sizeof( SIZE_HEAD ) );
		memcpy( &sz, (UBYTE*)( sizes[res+1] ), sizeof( SIZE_HEAD ) );
#else
		pos = (UBYTE*)sizes[res+1];
		sz.len = get_word( &pos );
		sz.nfonts = get_word( &pos );
		sz.dpi = get_long( &pos );
#endif
		if( find_m_flib_font( str, pos, sz.nfonts, &fn ) ) {
			break;
		}
		sizes[res] = 0x7FFFFFFFL;
	}
	if( i >= no_of_sizes/2 ) {
		return ( FALSE );
	}

	/* Gefunden */
	font->status.flib = TRUE;
	font->status.flib_nr = fnr;
	font->offset = fn.start;
	font->len = fn.len;
	strcpy( font->datei, doc->flib_name[fnr] );
	return ( TRUE );
}


/* liefert TRUE zurueck, wenn eine Datei mit dem Zeichensatz gefunden wurde */
BOOLEAN find_font_datei( DVI_DOC *doc, LONG mag, LONG toleranz, FONT *font )
{
	LONG imag, itoleranz, i, minmag, mintol;
	UBYTE dat[128];

	font->status.vf = FALSE;
	for( i = 0; i < doc->no_of_flib; i++ ) {   /* Zuerst nach Mattes-Flib suchen */
		if((doc->flib[i] < 0L)&&  strstr( doc->flib_head[i].magic, "FLIB" ) ) {
			open_m_flib( doc, doc->flib_name[i] );
		}
		if((doc->flib[i] > 0)  &&  find_m_flib( doc, font, mag, toleranz, (SWORD)i ) ) {
			return ( TRUE );
		}
	}

	imag = ( doc->h_dpi*mag )/1000L;
	itoleranz = ( doc->h_dpi*toleranz )/1000L;
#ifndef __MSDOS__
#ifdef PAS_FLIB
	/* Dann nach alter Flib suchen (Jaja, die alten Z�pfe...) */
	/* Aber nucht mehr mit MSDOS! */
	for( i = 0; i < 64; i++ ) {
		if( labs( doc->groessen[i]+imag ) < itoleranz ) {
			break;
		}
	}
	if( i < 64 ) {
		sprintf( dat, "%s\\pk%04i", doc->suchpfad1, -doc->groessen[i] );
		if((doc->groessen[i] != flib_size)||(a_flib <= 0)) {
			Mfree( a_flib );
			a_flib = 0;
			flib_size = doc->groessen[i];
			if((open_a_flib( dat ) > 0)&&(find_a_flib( font ) > 0)) {
				strcpy( font->datei, dat );
				return ( TRUE );
			}
		}
		else if( find_a_flib( font ) > 0 ) {
			strcpy( font->datei, dat );
			return ( TRUE );
		}
	}
#endif
#endif

	font->status.flib = FALSE;
	font->offset = 0;
	if( VERSION == LINDNER_TEX ) {
		itoleranz = toleranz;
		imag = mag;
	}
	minmag = 0;
	mintol = itoleranz;

	/* find closest size */
	for( i = 0; i < 64; i++ ) {
		if( labs( doc->groessen[i]-imag ) < mintol ) {
			mintol = labs( doc->groessen[i]-imag );
			minmag = doc->groessen[i];
		}
	}

	/* size found? */
	if( minmag == 0 ) {
		return ( FALSE );
	}
	imag = minmag;

	if( VERSION == LINDNER_TEX ) {
		sprintf( dat, "%s\\mag____%li.%.3li\\%s.pk", doc->suchpfad1, imag/1000, imag%1000, font->datei );
	}
	else if( VERSION == STRUNK_TEX ) {
		sprintf( dat, "%s\\font%.4li\\%s.pk", doc->suchpfad1, imag, font->datei );
	}
	else if( VERSION == EM_TEX ) {
		sprintf( dat, "%s\\%lidpi\\%s.pk", doc->suchpfad1, imag, font->datei );
	}
	else if( VERSION == DIRECT_TEX ) {
		sprintf( dat, "%s\\%.4li\\%s", doc->suchpfad1, imag, font->datei );
	}
	else if( VERSION == MIK_TEX ) {
		// the MIK_TEX search requires some more efforts ...
		char searchpath[1024];

		// default value ...
		sprintf( dat, "%s\\dpi%li\\%s.pk", doc->suchpfad1, imag, font->datei );

#ifndef _MSC_VER
		sprintf( searchpath, "%s/.", doc->suchpfad1 );
#else
		sprintf( searchpath, "%s\\*", doc->suchpfad1 );
#endif

#ifndef _MSC_VER
		// find filenames
		DIR *dir;                          /* Schnittstellen zum BS */

		dir = opendir( searchpath );
		if( dir == NULL ) {
			dbg->warning( "savegame_frame_t::savegame_frame_t()", "Couldn't read directory." );
		}
		else {
			const dirent * entry;
			do {
				entry = readdir( dir );
				if( entry != NULL ) {
					if((entry->d_name[0] != '.')||  ((entry->d_name[1] != '.')&&(entry->d_name[1] != 0)) ) {
						if( check( entry->d_name, suffix ) ) {
							if( !use_pak_extension ) {
								add_file( entry->d_name, "", not_cutting_extension );
							}
							else {
								// this is a savegame:
								// read also the pak extension
								loadsave_t test;
								char p[1024];
								sprintf( p, "%s%s", SAVE_PATH_X, entry->d_name );
								test.rd_open( p );
								add_file( entry->d_name, test.get_pak_extension(), not_cutting_extension );
							}
						}
					}
				}
			} while( entry != NULL );
			closedir( dir );
		}
#else
		{
			struct _finddata_t entry;
			long hfind;

			hfind = _findfirst( searchpath, &entry );
			if( hfind == -1 ) {
				// could not read directory ....
			}
			else {
				do {
					// now check for right file
					sprintf( dat, "%s\\%s\\dpi%li\\%s.pk", doc->suchpfad1, entry.name, imag, font->datei );
					if( Fattrib( dat, FALSE, 0 ) >= 0 ) {
						// found!
						strcpy( font->datei, dat );
						return ( TRUE );
					}
				} while( _findnext( hfind, &entry ) == 0 );
			}
		}
#endif
	}
	if( Fattrib( dat, FALSE, 0 ) >= 0 ) {
		strcpy( font->datei, dat );
		return ( TRUE );
	}
	/* zweiten Suchpfad probieren */
	if( VERSION == LINDNER_TEX ) {
		sprintf( dat, "%s\\mag____%li.%.3li\\%s.pk", doc->suchpfad2, imag/1000, imag%1000, font->datei );
	}
	else if( VERSION == STRUNK_TEX ) {
		sprintf( dat, "%s\\font%.4li\\%s.pk", doc->suchpfad2, imag, font->datei );
	}
	else if( VERSION == EM_TEX ) {
		sprintf( dat, "%s\\%lidpi\\%s.pk", doc->suchpfad2, imag, font->datei );
	}
	else if( VERSION == DIRECT_TEX ) {
		sprintf( dat, "%s\\%.4li\\%s", doc->suchpfad2, imag, font->datei );
	}
	else if( VERSION == MIK_TEX ) {
		sprintf( dat, "%s\\dpi%li\\%s.pk", doc->suchpfad2, imag, font->datei );
	}
	if( Fattrib( dat, FALSE, 0 ) >= 0 ) {
		strcpy( font->datei, dat );
		return ( TRUE );
	}

	return ( FALSE );
}


/* Eigentliche Suchroutine */
SWORD finde_font( DVI_DOC *doc, FONT *font, LONG mag )
{
	UBYTE dat[128];

	if( doc->groessen[0] <= 0 ) {
		if( VERSION == MIK_TEX ) {
			struct _finddata_t entry;
			long hfind;
			char path[1024];

			sprintf( path, "%s\\*.*", doc->suchpfad1 );
			hfind = _findfirst( path, &entry );
			if( hfind != -1 ) {
				do {
					// now check for right file
					if( entry.name[0] != '.' ) {
						sprintf( path, "%s\\%s", doc->suchpfad1, entry.name );
						read_mags( doc, path );
					}
				} while( _findnext( hfind, &entry ) == 0 );
			}
		}
		else {
			read_mags( doc, doc->suchpfad1 );
		}
		read_mags( doc, doc->suchpfad2 );
		if( doc->groessen[0] == 0 ) {
			doc->groessen[0] = 1;   /* Vielleicht gibt es ja Flib; WIr haben es probiert! */
		}
	}

	mag = ( mag+1 )&0x7FFE;
	if( mag == 1094 ) {
		mag = 1095;
	}
	if( mag == 3584 ) {
		mag = 3583;
	}

#ifdef DEBUG_FONT
	strncpy( font->name, font->datei, 9 );
	font->size = (SWORD)mag;
#endif

	if( !find_font_datei( doc, mag, TOLERANZ, font ) ) {
		/* Nach virtuellem Font suchen: */
		sprintf( dat, "%s\\%s.vf", doc->suchpfad1, font->datei );
		if( Fattrib( dat, FALSE, 0 ) >= 0 ) {
			strcpy( font->datei, dat );
			font->status.flib = FALSE;
			font->status.vf = TRUE;
			font->offset = 0;
			return TRUE;
		}
		/* Auch auf dem zweiten Suchpfad! */
		sprintf( dat, "%s\\%s.vf", doc->suchpfad2, font->datei );
		if( Fattrib( dat, FALSE, 0 ) >= 0 ) {
			strcpy( font->datei, dat );
			font->status.flib = FALSE;
			font->status.vf = TRUE;
			font->offset = 0;
			return TRUE;
		}

		/* Ham wa nich */
		add_to_miss( doc, doc->datei, font->datei, mag );

		/* Aber vielleicht jetzt? */
		if( TRUE || MISSING_FONT_GENERATE[0] != 0 ) {
			doc->groessen[0] = 0;   /* Groessen neu einlesen */
			if( VERSION == MIK_TEX ) {
				struct _finddata_t entry;
				long hfind;
				char path[1024];

				sprintf( path, "%s\\*.*", doc->suchpfad1 );
				hfind = _findfirst( path, &entry );
				if( hfind != -1 ) {
					do {
						// now check for right file
						if( entry.name[0] != '.' ) {
							sprintf( path, "%s\\%s", doc->suchpfad1, entry.name );
							read_mags( doc, path );
						}
					} while( _findnext( hfind, &entry ) == 0 );
				}
			}
			else {
				read_mags( doc, doc->suchpfad1 );
			}
			read_mags( doc, doc->suchpfad2 );
			if( doc->groessen[0] == 0 ) {
				doc->groessen[0] = 1;   /* Vielleicht gibt es ja Flib; WIr haben es probiert! */
			}
			if( find_font_datei( doc, mag, TOLERANZ, font ) ) {
				return TRUE;
			}
		}

		/* Hier soll irgentwann ein noch �hnlicher gesucht werden */

		/* Vielleicht gibt es ihn so? */
		if( mag != 1000 ) {
			if( find_font_datei( doc, 1000, TOLERANZ, font ) ) {
				return TRUE;
			}
		}

		font->chk_sum = 0L;
		strcpy( font->datei, "cmr10" );
		if( find_font_datei( doc, mag, TOLERANZ, font ) ) {
			return TRUE;
		}

		if( mag != 1000 ) {
			if( find_font_datei( doc, 1000, TOLERANZ, font ) ) {
				return TRUE;
			}
		}

		Tos_Fatal( doc, mag, ENOREPL );
		return FALSE;
	}
	return TRUE;
}


